package com.taoyuanx.boot.version;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.taoyuanx.boot.anno.ApiVersion;

public class MultiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
	
	    private static final Logger log = LoggerFactory.getLogger(MultiVersionRequestMappingHandlerMapping.class);
	
	    private final static Map<String,HandlerMethod> HANDLER_METHOD_MAP = new HashMap<>();
	
	    /**
	     *  匹配规则  映射路径_版本号  mapping_version hello_version
	     *  多版本处理handlermethod存储集合 
	     */
	    private final static String HANDLER_METHOD_KEY_PATTERN = "%s_v%s";  
	    private List<ApiVersionCodeDiscoverer> apiVersionCodeDiscoverers = new ArrayList<>();
	    @Override
	    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
	        ApiVersion apiVersionAnnotation = method.getAnnotation(ApiVersion.class);
	        if (apiVersionAnnotation != null) {
	            registerMultiVersionApiHandlerMethod(handler, method, mapping, apiVersionAnnotation);
	            return;
	        }
	        super.registerHandlerMethod(handler, method, mapping);
	    }
	
	    @Override
	    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	        HandlerMethod handleMethod = lookupMultiVersionApiHandlerMethod(lookupPath, request) ;
	        if (handleMethod != null)
	            return handleMethod;
	        handleMethod =   super.lookupHandlerMethod(lookupPath, request);
	        if(handleMethod==null) throw new NoHandlerFoundException(lookupPath, request.getRequestURI(), null);
	        return handleMethod;
	    }
	
	    public void registerApiVersionCodeDiscoverer(ApiVersionCodeDiscoverer apiVersionCodeDiscoverer){
	        if(!apiVersionCodeDiscoverers.contains(apiVersionCodeDiscoverer)){
	            apiVersionCodeDiscoverers.add(apiVersionCodeDiscoverer);
	        }
	    }
	
	    private void registerMultiVersionApiHandlerMethod(Object handler, Method method, RequestMappingInfo mapping, ApiVersion version ) {
	    	HandlerMethod handlerMethod = super.createHandlerMethod(handler, method);
	    	Set<String> patterns = mapping.getPatternsCondition().getPatterns();
	    	for(String mappingPath:patterns){
	    		 String mappingKey=String.format(HANDLER_METHOD_KEY_PATTERN,mappingPath,version.value());
	    		 log.debug("多版本控制注册版本信息为{},对应方法为{}",mappingKey,method.getName());
	    		 HANDLER_METHOD_MAP.put(mappingKey, handlerMethod);
	    	}
	    }
	
	    private HandlerMethod lookupMultiVersionApiHandlerMethod(String lookupPath, HttpServletRequest request) {
	    	Double version = tryResolveApiVersion(request);
	        if (null !=version) {
	            String mappingKey = String.format(HANDLER_METHOD_KEY_PATTERN, lookupPath, version);
	            HandlerMethod handlerMethod = (HandlerMethod) HANDLER_METHOD_MAP.get(mappingKey);
	            log.debug("多版本控制处理映射路径为{}",mappingKey);
	            return handlerMethod;
	        }
	        return null;
	    }
	
	    private Double tryResolveApiVersion(HttpServletRequest request) {
	        for (int i = 0; i < apiVersionCodeDiscoverers.size(); i++) {
	            ApiVersionCodeDiscoverer apiVersionCodeDiscoverer = apiVersionCodeDiscoverers.get(i);
	            Double versionCode = apiVersionCodeDiscoverer.getVersionCode(request);
	            if(null !=versionCode)
	                return versionCode;
	        }
	        return null;
	    }
	   
}

